package scatter.common.rest.service;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.Update;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import io.swagger.annotations.ApiModelProperty;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import scatter.common.pojo.dto.RelDto;
import scatter.common.pojo.form.*;
import scatter.common.pojo.po.BasePo;
import scatter.common.pojo.po.BaseTreePo;
import scatter.common.rest.exception.BusinessException;
import scatter.common.rest.tools.InterfaceTool;
import scatter.common.rest.tools.StringTool;

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static scatter.common.pojo.po.BaseTreePo.INIT_LEVEL;
import static scatter.common.pojo.po.BaseTreePo.MAX_LEVEL;

/**
 * 所有service接口的父接口，以实现通用功能
 * Created by yangwei
 * Created at 2019/7/23 14:30
 */
public interface IBaseService<Po> extends IService<Po>, InterfaceTool {


    /**
     * 判断数据是否存在
     * @param id
     * @return
     */
    default boolean existById(String id) {
        Assert.hasText(id,"id 不能为空");

        return count( Wrappers.<Po>query().eq(BasePo.COLUMN_ID,id)) > 0;
    }

    /**
     * 根据主键增加一个字段的值，
     * @param id
     * @param column
     * @param num
     * @return
     */
    default boolean plusForColumnById(String id,SFunction<Po, ?> column,Object num){
        Assert.notNull(column,"column不能为空");
        Assert.hasText(id,"columnId不能为空");

        String columnName  = SFunctionHelperTool.columnToString(column);
        String sql = StrUtil.format(" {} = {} + {} ",columnName,columnName,num);
        return update(Wrappers.<Po>update().setSql(sql).eq(BasePo.COLUMN_ID,id));
    }

    /**
     * 判断数据是否存在
     * @param columnId
     * @param column Po::getId
     * @return
     */
    default boolean existByColumn(String columnId, SFunction<Po, ?> column) {
        Assert.notNull(column,"column不能为空");
        Assert.hasText(columnId,"columnId不能为空");
        return count( Wrappers.<Po>query().lambda().eq(column,columnId)) > 0;
    }

    /**
     * 断言根据该列查询是否存在或不存在
     * @param columnId
     * @param column
     * @param exist true=断言存在，false=断言不存在
     */
    default void assertByColumn(String columnId, SFunction<Po, ?> column,boolean exist) {
        Assert.notNull(column,"column不能为空");
        Assert.hasText(columnId,"columnId不能为空");
        boolean existByColumn = existByColumn(columnId, column);
        if(exist == existByColumn){
            return;
        }
        String realDbColumn = SFunctionHelperTool.columnToString(column);
        // 获取swagger注解
        SerializedLambda resolve = LambdaUtils.resolve(column);
        String propertyName = StringTool.lineToHump(realDbColumn);
        String columnLabel = propertyName;
        Field field = ReflectUtil.getField(resolve.getImplClass(), propertyName);
        if (field != null) {
            ApiModelProperty apiModelProperty = AnnotationUtil.getAnnotation(field, ApiModelProperty.class);
            if (apiModelProperty != null && !isStrEmpty(apiModelProperty.value())) {
                // 取第一个逗号逗号分隔的字符作为提示标签
                columnLabel = apiModelProperty.value().split(",")[0].split("，")[0];
            }
        }
        if (exist) {
            Assert.isTrue(existByColumn,columnLabel + " " + columnId + " " +  "不存在");
        }else {
            Assert.isTrue(!existByColumn,columnLabel + " " + columnId + " " +  "已存在");
        }
    }

    /**
     * 断言数据是否存在
     * @param queryWrapper
     * @param exist true=断言存在，false=断言不存在
     * @param msg 不满足条件时的提示消息
     */
    default void assertByWrapper(Wrapper<Po> queryWrapper,boolean exist,String msg){
        int count = count(queryWrapper);
        boolean existByWrapper = count > 0;
        if (exist) {
            Assert.isTrue(existByWrapper,msg);
        }else {
            Assert.isTrue(!existByWrapper,msg);
        }
    }


    /**
     * 根据id查询
     * @param id
     * @return
     */
    Po queryById(String id);
    /**
     * 删除
     * @param id
     * @return
     */
    boolean deleteById(String id);

    /**
     * 根据属性字段删除
     * @param columnId
     * @param column
     * @return
     */
    boolean deleteByColumn(String columnId,  SFunction<Po, ?> column);

    /****************************** 扩展辅助功能 *************************************************/


    /**
     * 更新注解处理
     * 仅限updateform添加注解使用 SetNullWhenNull 注解支持
     * @param updateWrapper
     * @param query
     */
    default void annotationSupportUpdateWrapper(Update updateWrapper, Object query){

        if (query == null) {
            return;
        }
        for (Field field : ReflectUtil.getFields(query.getClass())) {

            Ignore ignore = AnnotationUtil.getAnnotation(field, Ignore.class);
            if (ignore != null) {
                continue;
            }
            Object fieldValue = ReflectUtil.getFieldValue(query, field);
            String columnName = StringTool.humpToLine(field.getName());
            if (fieldValue == null) {
                SetNullWhenNull setNullWhenNull = AnnotationUtil.getAnnotation(field, SetNullWhenNull.class);
                if (setNullWhenNull != null) {
                    updateWrapper.set(columnName, null);
                }
            }

        }// end for
    }

    /**
     * 查询注解处理
     * @param queryWrapper
     * @param query 查询实体载体
     */
    default void annotationSupportQueryWrapper(Wrapper<Po> queryWrapper, Object query){

        if (query == null) {
            return;
        }

        // 补充一个条件，否则在拼接or的时候会拼接不对，而是and
        ((AbstractWrapper) queryWrapper).apply(true, "true");
        boolean userCustomOrderBy = false;
        if (BaseQueryForm.class.isAssignableFrom(query.getClass())) {


            String orderBy = ((BaseQueryForm) query).getOrderBy();
            if (StrUtil.isNotEmpty(orderBy)) {
                userCustomOrderBy = true;
                String[] orderBys = orderBy.split(",");
                for (String orderByItem : orderBys) {
                    String[] orderByItems = orderByItem.split("-");
                    String columnName = StringTool.humpToLine(orderByItems[0]);
                    ((AbstractWrapper) queryWrapper).orderBy(true, orderByItems.length > 1 ? "1".equals(orderByItems[1]) : true, columnName);
                }
            }
        }

        Map<String, OrderBy> orderByMap = new HashMap<>();
        if (!userCustomOrderBy) {
            // 类上注解支持
            OrderBy orderByClass = AnnotationUtil.getAnnotation(query.getClass(), OrderBy.class);
            if (orderByClass != null) {
                String columnName = StringTool.humpToLine(orderByClass.value());
                if (!isStrEmpty(columnName)) {
                    orderByMap.put(columnName,orderByClass);
                }else {
                    throw new RuntimeException(query.getClass().getName() + "指定了OrderBy但未指定列名");
                }
            }
        }


        for (Field field : ReflectUtil.getFields(query.getClass())) {
            Object fieldValue = ReflectUtil.getFieldValue(query, field);
            Ignore ignore = AnnotationUtil.getAnnotation(field, Ignore.class);
            if (ignore != null) {
                continue;
            }

            // orderby处理
            if (!userCustomOrderBy) {
                OrderBy orderBy = AnnotationUtil.getAnnotation(field, OrderBy.class);
                if (orderBy != null) {
                    String columnName = StringTool.humpToLine(orderBy.value());
                    if (isStrEmpty(columnName)) {
                        columnName = StringTool.humpToLine(field.getName());
                    }
                    orderByMap.put(columnName,orderBy);
                }
            }


            In in = AnnotationUtil.getAnnotation(field, In.class);
            if (in != null && fieldValue != null) {
                Object finalFieldValue = fieldValue;

                (((AbstractWrapper) queryWrapper)).in(StringTool.humpToLine(field.getName()), ((Collection) finalFieldValue));
                setObjectValueNull(queryWrapper.getEntity(), field.getName());
                continue;
            }

            if (fieldValue == null) {
                continue;
            }
            // like 处理
            Ne ne = AnnotationUtil.getAnnotation(field, Ne.class);
            if(ne != null){
                String neValue = ne.value();
                if (!isStrEmpty(neValue)) {
                    ((AbstractWrapper) queryWrapper).ne( StringTool.humpToLine(neValue), fieldValue);
                }else {
                    ((AbstractWrapper) queryWrapper).ne( StringTool.humpToLine(field.getName()), fieldValue);
                    setObjectValueNull(queryWrapper.getEntity(), field.getName());
                }
                continue;
            }
            // like 处理
            Like like = AnnotationUtil.getAnnotation(field, Like.class);
            if(like != null){
                ((AbstractWrapper) queryWrapper).like( StringTool.humpToLine(field.getName()), fieldValue);
                setObjectValueNull(queryWrapper.getEntity(), field.getName());
                continue;
            }
            // 大于 处理
            Gt gt = AnnotationUtil.getAnnotation(field, Gt.class);
            if (gt != null) {
                String gtValue = gt.value();
                if (isStrEmpty(gtValue)) {
                    throw new RuntimeException("你必须指定比较字段的名称");
                }
                if (gt.eq()) {
                    ((AbstractWrapper) queryWrapper).ge( StringTool.humpToLine(gtValue), fieldValue);

                }else {
                    ((AbstractWrapper) queryWrapper).gt( StringTool.humpToLine(gtValue), fieldValue);
                }

                continue;
            }
            // 小于 处理
            Lt lt = AnnotationUtil.getAnnotation(field, Lt.class);
            if (lt != null) {
                String ltValue = lt.value();
                if (isStrEmpty(ltValue)) {
                    throw new RuntimeException("你必须指定比较字段的名称");
                }
                if (lt.eq()) {
                    ((AbstractWrapper) queryWrapper).le( StringTool.humpToLine(ltValue), fieldValue);

                }else {
                    ((AbstractWrapper) queryWrapper).lt( StringTool.humpToLine(ltValue), fieldValue);
                }
                continue;
            }

            Or or = AnnotationUtil.getAnnotation(field, Or.class);
            if (or != null) {
                Object finalFieldValue = fieldValue;
                ((AbstractWrapper) ((AbstractWrapper) queryWrapper).or()).eq(StringTool.humpToLine(field.getName()), finalFieldValue);
                setObjectValueNull(queryWrapper.getEntity(), field.getName());
                continue;
            }

        }// end for

        if (!orderByMap.isEmpty()) {
            orderByMap.entrySet().stream().sorted(Comparator.comparingInt(e -> e.getValue().order()))
                    .forEach((entry)->{
                        ((AbstractWrapper) queryWrapper).orderBy(true, entry.getValue().asc(), entry.getKey());
                    });
        }
    }


    /**
     * 设置对象值为空
     * @param obj
     * @param fieldName
     */
    default void setObjectValueNull(Object obj,String fieldName){
        if (obj != null) {
            try {
                ReflectUtil.setFieldValue(obj,fieldName,null);
            }catch (Exception e){
                LoggerFactory.getLogger(IBaseService.class).warn(e.getMessage() + "你利用了查询参数注解，在将原始值设置为空时出错了，但这也许不影响运行的正确性",e);
            }
        }
    }


    /**************************以下为树操作*******************************************/

    /**
     * 查询第一级
     * @return
     */
    default List<Po> getRoot(){
        return list(Wrappers.<Po>query().eq(BaseTreePo.COLUMN_LEVEL,INIT_LEVEL).isNull(BaseTreePo.COLUMN_PARENT_ID));
    }
    /**
     * 查询第一级
     * @return
     */
    default List<Po> getRoot(Po query){
        return list(Wrappers.<Po>query(query).eq(BaseTreePo.COLUMN_LEVEL,INIT_LEVEL).isNull(BaseTreePo.COLUMN_PARENT_ID));
    }

    /**
     * 查询第一级并且等于该id
     * @return
     */
    default Po getRoot(String id){
        Assert.hasText(id, "id不能为空");
        return getOne(Wrappers.<Po>query().eq(BaseTreePo.COLUMN_LEVEL,INIT_LEVEL).isNull(BaseTreePo.COLUMN_PARENT_ID).eq(BaseTreePo.COLUMN_ID,id));

    }
    /**
     * 查询子一级节点
     * @param parentId
     * @return
     */
    default List<Po> getChildren(String parentId){
        Assert.hasText(parentId,"parentId不能为空");
        return list(Wrappers.<Po>query().eq(BaseTreePo.COLUMN_PARENT_ID,parentId));
    }
    /**
     * 查询子一级节点
     * @param parentId
     * @param query
     * @return
     */
    default List<Po> getChildren(String parentId, Po query){
        Assert.hasText(parentId,"parentId不能为空");
        return list(Wrappers.<Po>query(query).eq(BaseTreePo.COLUMN_PARENT_ID,parentId));
    }

    /**
     * 查询子一级节点,是否有子节点
     * @param parentId
     * @return
     */
    default boolean hasChildren(String parentId){
        int count = getChildrenCount(parentId);
        return count > 0;
    }

    /**
     * 获取所有的子孙节点
     * @param parentId
     * @return
     */
    default List<Po> getAllChildren(String parentId){
        if (parentId == null) {
            return null;
        }
        Po parent = getById(parentId);
        if (parent == null) {
            return null;
        }
        Map<String,Object> p = new HashMap<>(1);
        p.put(BaseTreePo.COLUMN_PARENT_ID + ((BaseTreePo)parent).getLevel(),parentId);
        return listByMap(p);
    }

    /**
     * 获取子一级节点的数目
     * @param parentId
     * @return
     */
    default int getChildrenCount(String parentId){

        Assert.hasText("parentId","parentId不能为空");
        Map<String,Object> p = new HashMap<>(1);
        p.put(BaseTreePo.COLUMN_PARENT_ID,parentId);
        return count(Wrappers.<Po>query().eq(BaseTreePo.COLUMN_PARENT_ID,parentId));
    }
    /**
     * 查询父级
     * @param id
     * @return
     */
    default Po getParent(String id){
        if (id == null) {
            return null;
        }
        Po po = getById(id);
        if (po != null) {
            return getById(((BaseTreePo)po).getParentId());
        }
        return null;
    }

    /**
     * 获取所有父级
     * @param id
     * @return
     */
    default List<Po> getAllParents(String id){
        if (id == null) {
            return null;
        }
        BaseTreePo dbPo = (BaseTreePo) getParent(id);
        if (dbPo == null) {
            return null;
        }
        List<String> parentIds = new ArrayList<>(MAX_LEVEL - 1);
        if (dbPo.getParentId1() != null) {
            parentIds.add(dbPo.getParentId1());
        }
        if (dbPo.getParentId2() != null) {
            parentIds.add(dbPo.getParentId2());
        }
        if (dbPo.getParentId3() != null) {
            parentIds.add(dbPo.getParentId3());
        }
        if (dbPo.getParentId4() != null) {
            parentIds.add(dbPo.getParentId4());
        }
        if (dbPo.getParentId5() != null) {
            parentIds.add(dbPo.getParentId5());
        }
        if (dbPo.getParentId6() != null) {
            parentIds.add(dbPo.getParentId6());
        }
        if (dbPo.getParentId7() != null) {
            parentIds.add(dbPo.getParentId7());
        }
        if (dbPo.getParentId8() != null) {
            parentIds.add(dbPo.getParentId8());
        }
        if (dbPo.getParentId9() != null) {
            parentIds.add(dbPo.getParentId9());
        }
        if (dbPo.getParentId10() != null) {
            parentIds.add(dbPo.getParentId10());
        }
        return list(Wrappers.<Po>query().in(BasePo.COLUMN_ID,parentIds).orderByAsc(BaseTreePo.COLUMN_LEVEL));
    }

    /**
     * 根据ID查询所有父级包括自己
     * @param id
     * @return
     */
    default List<Po> getAllParentsAndSelf(String id){
        if (id == null) {
            return null;
        }
        BaseTreePo dbPo = (BaseTreePo) getById(id);
        if (dbPo == null) {
            return null;
        }
        List<String> parentIds = new ArrayList<>(MAX_LEVEL - 1);
        if (dbPo.getParentId1() != null) {
            parentIds.add(dbPo.getParentId1());
        }
        if (dbPo.getParentId2() != null) {
            parentIds.add(dbPo.getParentId2());
        }
        if (dbPo.getParentId3() != null) {
            parentIds.add(dbPo.getParentId3());
        }
        if (dbPo.getParentId4() != null) {
            parentIds.add(dbPo.getParentId4());
        }
        if (dbPo.getParentId5() != null) {
            parentIds.add(dbPo.getParentId5());
        }
        if (dbPo.getParentId6() != null) {
            parentIds.add(dbPo.getParentId6());
        }
        if (dbPo.getParentId7() != null) {
            parentIds.add(dbPo.getParentId7());
        }
        if (dbPo.getParentId8() != null) {
            parentIds.add(dbPo.getParentId8());
        }
        if (dbPo.getParentId9() != null) {
            parentIds.add(dbPo.getParentId9());
        }
        if (dbPo.getParentId10() != null) {
            parentIds.add(dbPo.getParentId10());
        }
        parentIds.add(id);
        return list(Wrappers.<Po>query().in(BasePo.COLUMN_ID,parentIds).gt(BaseTreePo.COLUMN_LEVEL,1).orderByAsc(BaseTreePo.COLUMN_LEVEL));
    }

    /**
     * 检查树结构是否完整，该检查一旦检查到异常数据就停止，而不会汇总出所有数据的异常，因为父级有异常子级就不保证正确了，所以先处理了再检查
     * @param parent 对parent本身没有做检查，启用必须传null对全量做检查，如果不传null请确保parent本身的正确
     */
    default void checkTreeStruct(BaseTreePo parent) {

        int level = parent == null? INIT_LEVEL:parent.getLevel() + 1;
        Map<String, String> parentIdx = new HashMap<>(10);
        for (int i = 1; i < MAX_LEVEL; i++) {
            String fieldName = BaseTreePo.PROPERTY_PARENT_ID + i;
            Object fieldValueObj = ReflectUtil.getFieldValue(parent, fieldName);
            String fieldValue = fieldValueObj == null ? null : fieldValueObj.toString();
            parentIdx.put(fieldName, parent == null ? null : fieldValue);
        }
        if (parent != null) {
            String fieldName = BaseTreePo.PROPERTY_PARENT_ID + parent.getLevel();
            parentIdx.put(fieldName, parent.getId());
        }
        List<BaseTreePo> children = null;
        if (parent == null) {
            children = (List<BaseTreePo>) getRoot();
        }else {
            children = (List<BaseTreePo>) getChildren(parent.getId());
        }
        if (!isEmpty(children)) {
            for (BaseTreePo po : children) {
                if(po.getLevel() != level){
                    throw new BusinessException("id=" + po.getId() + " level应该为"+ level +"实际为" + po.getLevel());
                }
                for (int i = 1; i < MAX_LEVEL; i++) {
                    String fieldName = BaseTreePo.PROPERTY_PARENT_ID + i;
                    Object fieldValueObj = ReflectUtil.getFieldValue(po, fieldName);
                    String fieldValue = fieldValueObj == null ? null : fieldValueObj.toString();
                    if( !isEqual(parentIdx.get(fieldName),fieldValue)){
                        throw new BusinessException("id=" + po.getId() + " "+ (fieldName) +"应该为"+ parentIdx.get(fieldName) +"实际为" + fieldValue);
                    }
                }
                checkTreeStruct(po);
            }
        }

    }
    /**
     * 根据id和父id查询
     * @param id
     * @param parentId
     * @return
     */
    default Po getByIdAndParentId(String id, String parentId){
        if (isStrAnyEmpty(id,parentId)) {
            throw new BusinessException("id 和 parentId" + "都不能为空");
        }
        return getOne(Wrappers.<Po>query().eq(BaseTreePo.COLUMN_PARENT_ID, parentId).eq(BaseTreePo.COLUMN_ID, id));
    }

    /**
     * 根据风节点，设置子节点parentIdx的值包括parentId本身
     * @param child
     * @param parentId
     * @return
     */
    default Po initParentIdXByParent(Po child, String parentId){
        if (isStrEmpty(parentId)) {
            return child;
        }
        Po parent = (Po) getById(parentId);
        return TreeServiceHelperTool.initParentIdXByParent(child, parent);
    }

    /**
     * 根据父节点，设置子节点parentIdx的值包括parentId本身
     * @param child
     * @param parent
     * @return
     */


    /**
     * 添加子节点
     * @param entity
     * @param parentId
     * @return
     */
    @Transactional
    default boolean insertChild(Po entity, String parentId){
        entity = initParentIdXByParent(entity, parentId);

        return save(entity);
    }

    /**
     * 将id节点移动到parentId下，包括所有子节点
     * @param id
     * @param parentId
     * @return  返回涉及到的数据条数
     */
    @Transactional
    default int moveNode(String id, String parentId){

        int result = 0;
        Assert.hasText(id,"移动的节点id不能为空");
        Po entity = getById(id);
        Assert.notNull(entity,"移动的节点不存在");
        if (isEqual(id,parentId)) {
            throw new IllegalArgumentException("不能将节点本身做为父节点");
        }
        entity = initParentIdXByParent(entity, parentId);
        // 更新开始 主要是把parentIdX可以更新为null
        UpdateWrapper<Po> update = Wrappers.update();
        update.set(BaseTreePo.COLUMN_PARENT_ID, ((BaseTreePo) entity).getParentId());
        update.eq(BasePo.COLUMN_ID, ((BaseTreePo) entity).getId());
        String propertyParentIdx = null;
        String columnParentIdx = null;
        for (int i = 1; i < MAX_LEVEL; i++) {
            columnParentIdx = BaseTreePo.COLUMN_PARENT_ID + i;
            propertyParentIdx = BaseTreePo.PROPERTY_PARENT_ID + i;
            update.set(columnParentIdx, ReflectUtil.getFieldValue(entity,propertyParentIdx));
        }
        boolean entityUpdateResult = update(entity,update);
        // 更新结束
        if(entityUpdateResult){
            result++;
        }
        List<Po> children = getChildren(id);
        if (!isEmpty(children)) {
            for (Po child : children) {
                result += moveNode(((BaseTreePo) child).getId(), id);
            }
        }
        return result;
    }
    /******************* 关系表相关 ****************************************/


    /**
     * 关系删除，仅限懒加载时使用
     *
     * @param mainId           主id，如：如果是角色分配功能，则为角色id
     * @param checkedOtherIds  已选择的被分配的id
     * @param uncheckeOtherIds 未选择的被分配的id
     */
    default boolean removeAssignRelLazy(String mainId, List<String> checkedOtherIds, List<String> uncheckeOtherIds, SFunction<Po, ?> main, SFunction<Po, ?> other) {
        return removeAssignRel(mainId, checkedOtherIds, null, true, main, other);
    }
    /**
     * 关系删除
     *
     * @param mainId           主id，如：如果是角色分配功能，则为角色id
     */
    default boolean removeAssignRel(String mainId,  SFunction<Po, ?> main) {
        return removeAssignRel(mainId, null, null, false, main, null);
    }
    /**
     * 关系处理，删除取消分配的数据
     * @param mainId 主id，如：如果是角色分配功能，则为角色id
     * @param checkedIds 已选择的被分配的id
     * @param uncheckeIds 未选择的被分配的id
     * @param isLazyLoad 标识页面的可选择数据是否为懒加载，如果不是懒加载会清空主id已绑定的所有数据
     * @return  返回真正需要checkedIds数据
     */
    default List<String> removeAssignRelWithReturn(String mainId, List<String> checkedIds, List<String> uncheckeIds,Boolean isLazyLoad, SFunction<Po,?> main, SFunction<Po,?> other){

        Assert.hasText(mainId, "mainId不能为空");
        Assert.notNull(main, "main不能为空");
        List<String> result = new ArrayList<>();
        boolean isLazy = (isLazyLoad != null && isLazyLoad);

        if (isLazy) {
            if (!isEmpty(uncheckeIds)) {
                Assert.notNull(other, "other不能为空");
                remove(Wrappers.<Po>lambdaQuery().eq(main,mainId).in(other,uncheckeIds));
            }
        }else {
            // 数据不是懒加载，且没有选中数据，则全部删除关系
            if (isEmpty(checkedIds)) {
                remove(Wrappers.<Po>lambdaQuery().eq(main,mainId));
            }else {
                Assert.notNull(other, "other不能为空");
                remove(Wrappers.<Po>lambdaQuery().eq(main,mainId).notIn(other,checkedIds));
            }
        }
        // 上面已经把不需要的已经删除完成
        // 查询数据库里还剩下的已选中的
        if (!isEmpty(checkedIds)) {
            Assert.notNull(other, "other不能为空");
            List<Po> listDb = list(Wrappers.<Po>lambdaQuery().eq(main, mainId).in(other, checkedIds));
            // 已经选中的，除去数据库里已经存在的，是真正要添加的
            List<String> newRealCheckedIds = new ArrayList<>();
            List<?> checkedIdsInDb = listDb.stream().map(other).collect(Collectors.toList());
            for (String checkedId : checkedIds) {
                if (!checkedIdsInDb.contains(checkedId)) {
                    newRealCheckedIds.add(checkedId);
                }
            }
            result = newRealCheckedIds;
        }

        return result;
    }


        /**
		 * 关系处理，删除取消分配的数据
		 * @param mainId 主id，如：如果是角色分配功能，则为角色id
		 * @param checkedIds 已选择的被分配的id
		 * @param uncheckeIds 未选择的被分配的id
		 * @param isLazyLoad 标识页面的可选择数据是否为懒加载，如果不是懒加载会清空主id已绑定的所有数据
		 */
    default boolean removeAssignRel(String mainId, List<String> checkedIds, List<String> uncheckeIds,Boolean isLazyLoad, SFunction<Po,?> main, SFunction<Po,?> other){

        List<String> strings = removeAssignRelWithReturn(mainId, checkedIds, uncheckeIds, isLazyLoad, main, other);
        // 这里直接返回 true 因为上面的返回值不代表没有成功
        return true;
    }

    /**
     * 分配支持懒加载
     * @param mainId
     * @param checkedIds
     * @param uncheckeIds
     * @param isLazyLoad
     * @param main
     * @param other
     * @param mapper
     */
    default boolean removeAndAssignRel(String mainId, List<String> checkedIds, List<String> uncheckeIds,Boolean isLazyLoad, SFunction<Po,?> main, SFunction<Po,?> other, Function<RelDto, ? extends Po> mapper){
        List<String> realCheckedIds = removeAssignRelWithReturn(mainId, checkedIds, uncheckeIds, isLazyLoad, main, other);
        return assignRel(mainId, realCheckedIds, mapper);
    }
    /**
     * 添加已选数据
     * @param mainId
     * @param checkedIds
     * @param mapper
     */
    default boolean assignRel(String mainId, List<String> checkedIds, Function<RelDto, ? extends Po> mapper){
        if (!isEmpty(checkedIds)) {
            List<Po> insert = new ArrayList<>(checkedIds.size());
            return saveBatch(checkedIds.stream().map(checkedId-> mapper.apply(new RelDto(mainId,checkedId))).collect(Collectors.toList()));
        }
        return false;
    }

    /**
     * 删除并绑定数据
     * @param mainId
     * @param checkedIds
     * @param mapper
     */
    default boolean removeAndAssignRel(String mainId, List<String> checkedIds,SFunction<Po, ?> main, Function<RelDto, ? extends Po> mapper){
        removeAssignRel(mainId, main);
        return assignRel(mainId, checkedIds, mapper);
    }


    /**
     * 可以根据任务唯一字段进行指更新
     * 对{@link  IService#saveOrUpdateBatch(java.util.Collection)}  的一个补充，其只能根据主键id更新
     * @param entityList
     * @return
     */
    default boolean saveOrUpdateBatchByUniqueColumn(Collection<Po> entityList, SFunction<Po, ?> column) {
        return saveOrUpdateBatchByUniqueColumn(entityList,column,DEFAULT_BATCH_SIZE);
    }

    /**
     * 实时从数据库查询是否指定字段已存在
     * 可以根据任务唯一字段进行指更新，不适用主键，如果主键请使用mybatisPlus指定方法{@link IService#saveOrUpdateBatch(java.util.Collection, int)}
     * 对{@link IService#saveOrUpdateBatch(java.util.Collection, int)} 的一个补充，其只能根据主键id更新
     * @param entityList
     * @param batchSize
     * @return
     */
    boolean saveOrUpdateBatchByUniqueColumn(Collection<Po> entityList, SFunction<Po, ?> column, int batchSize);

    /**
     * 可以根据任务唯一字段进行指更新
     * 对{@link IService#updateBatchById(java.util.Collection)} 的一个补充，其只能根据主键id更新
     * @param entityList
     * @return
     */
    default boolean updateBatchByUniqueColumn(Collection<Po> entityList, SFunction<Po, ?> column) {
        return updateBatchByUniqueColumn(entityList,column,DEFAULT_BATCH_SIZE);
    }

    /**
     * 可以根据任务唯一字段进行指更新
     * 对{@link IService#updateBatchById(java.util.Collection,int)} 的一个补充，其只能根据主键id更新
     * @param entityList
     * @param batchSize
     * @return
     */
    boolean updateBatchByUniqueColumn(Collection<Po> entityList, SFunction<Po, ?> column, int batchSize);

    /**
     * 转换
     * @param pageQueryForm
     * @return
     */
    default Page convertPage(BasePageQueryForm pageQueryForm){
        Page pageQuery = new Page(((BasePageQueryForm) pageQueryForm).getCurrent(), ((BasePageQueryForm) pageQueryForm).getSize());

        return pageQuery;
    }
}
